import '../node_modules/less/dist/less.js'
import {compileScript,parse,rewriteDefault,compileTemplate,compileStyle} from '../node_modules/@vue/compiler-sfc/dist/compiler-sfc.esm-browser.js'
//import {minify as minify_css_inner} from './csso.mjs'

export function minifyCss(source){
    return source//minify_css_inner(source).css
}
/**
 * 编译less
 * @param {string} src
 * @returns
 */
export function lessc(src){
    let css=''
    less.render(src,{},function(err,ret){
        if(err){
           // reject(err)
           throw err
        }else{
           // resolve(ret.css)
            css=ret.css
        }
    });
    return css
}
/**
 * 编译ts
 * @param {string} src
 * @param {object} options
 * @returns
 */
export function tsc(src,options={}){
    if (!options.module) {
        options.module = 'ES2015'
    }
    throw new Error("lang ts not support");
    //return ts.transpile(src,options)
}

//编译vue模板
const COMP_IDENTIFIER = `_sfc`

function dbg_css(path) {
    return "\n/*# sourceURL=" + path + "*/";
}

function toCompileScript(descriptor, id) {
    if (descriptor.script || descriptor.scriptSetup) {
        const compiledScript = compileScript(descriptor, {
            inlineTemplate: true,
            id,
            defineModel:true,
            templateOptions: {
                ssr: false,
                ssrCssVars: descriptor.cssVars,
                compilerOptions: {

                }
            }
        })
        if (compiledScript.errors) {
            console.error(compiledScript.errors)
        }
        if (compiledScript.lang == 'ts') {
            compiledScript.content = tsc(compiledScript.content)
        }
        let code = ''
        code +=
            `\n` +
            rewriteDefault(compiledScript.content, COMP_IDENTIFIER)

        return [code, compiledScript.bindings]
    } else {
        //\nconst ${COMP_IDENTIFIER} = {}
        return [`const ${COMP_IDENTIFIER} = {};`, undefined]
    }
}
function toCompileTemplate(descriptor, id, bindingMetadata) {
    const templateResult = compileTemplate({
        source: descriptor.template.content,
        filename: descriptor.filename,
        id,
        scoped: descriptor.styles.some((s) => s.scoped),
        slotted: descriptor.slotted,
        ssr: false,
        ssrCssVars: descriptor.cssVars,
        isProd: true,
        compilerOptions: {
            bindingMetadata,
            expressionPlugins: undefined
        }
    })
    if (templateResult.errors.length) {
        console.error(templateResult.errors)
        return
    }
    return templateResult.code
}

export function sfc(source, filename) {
    const id = '_vue_sc_id'//incId()//hashId(filename)
    const { errors, descriptor } = parse(source, {
        filename,
        sourceMap: false
    })

    const hasScoped = descriptor.styles.some((s) => s.scoped)
    let clientCode = ''

    const appendSharedCode = (code) => {
        clientCode += code
    }
    if (hasScoped) {
        appendSharedCode(`const __scopeId_=(t=>t._getScopeId?t._getScopeId():(()=>{let e=0;return t._getScopeId=()=>(e++,"data-v-"+e),t._getScopeId()})())(window)\n`)
    }

    const clientScriptResult = toCompileScript(descriptor, id)
    if (!clientScriptResult) {
        return
    }

    const [clientScript, bindings] = clientScriptResult

    clientCode += clientScript
    // template
    // only need dedicated compilation if not using <script setup>
    if (descriptor.template && !descriptor.scriptSetup) {
        const clientTemplateResult = toCompileTemplate(descriptor, id, bindings)
        if (!clientTemplateResult) {

            return
        }
        clientCode += clientTemplateResult.replace(/\nexport function render/i,`\nif(!${COMP_IDENTIFIER}.render)${COMP_IDENTIFIER}.render=function `)
        //clientCode+=`\n${COMP_IDENTIFIER}.render=render`
    }
    if (hasScoped) {
        // clientCode="const __scoped"
      //  clientCode = clientCode.replace(/"data-v-_vue_sc_id"/g, "__scopeId_")
        clientCode = clientCode.replace(/data-v-_vue_sc_id>/g, "\"+__scopeId_+\">")
        appendSharedCode(
            `\n${COMP_IDENTIFIER}.__scopeId = __scopeId_`
        )
    }

    // styles
    let css = ''

    //let _lessc = lessc
    let hasLess = false
    for (const style of descriptor.styles) {
        if (style.module) {
            continue;
        }
        hasLess = hasLess || style.lang == 'less'
        let styleContent=style.content
        if (style.lang=='less'){
            styleContent=lessc(styleContent);
        }
        const styleResult = compileStyle({
            source: styleContent,
            filename,
            id,
            scoped: style.scoped,
            modules: !!style.module
        })
        if (styleResult.errors.length > 0) {
            // postcss uses pathToFileURL which isn't polyfilled in the browser
            // ignore these errors for now
            if (!styleResult.errors[0].message.includes('pathToFileURL')) {
                continue
            }
            console.error(styleResult.errors)
            // proceed even if css compile errors
        } else {
            css += styleResult.code + '\n';
        }
    }

    if (clientCode) {
        // clientCode=importToRequire(clientCode)

        if (css) {
            //  compiled.css = css.trim()
            css =minifyCss(css.trim());
            // if(hasLess){
            //     css = lessc(css)
            // }
            //css = _lessc(css, hasLess)

            if (filename) {
                css += dbg_css(filename + '.css')
            }
            //添加css
           // appendSharedCode(`\nObject.assign(${COMP_IDENTIFIER},((e,t)=>{let o=0,l=t.createElement("style");l.innerHTML=\`${css}\`;var n={mounted(){o++,1==o&&t.head.appendChild(l)},beforeDestroy(){o--,o<=0&&t.head.removeChild(l)}};e.mixins?e.mixins.push(n):e.mixins=[n]})(${COMP_IDENTIFIER},document))\n`)
           //  if (hasScoped){
           //      css = css.replace(//)
           //  }
            //\u0001
            if (hasScoped) {
                css = css.replace(/data-v-_vue_sc_id/g, "\u0001")
                css = css.replace(/_vue_sc_id/g, "\u0001")
            }
            appendSharedCode(`
\n;(function(e, style){
    const css = new CSSStyleSheet()
    css.replaceSync(style)
    let useIndex = 0
    const d=document
    const n = {
        mounted() {
            useIndex++
            if (1 == useIndex){
                d.adoptedStyleSheets=[...d.adoptedStyleSheets,css]
            }
        },
        beforeDestroy() {
            useIndex--
            if (useIndex <= 0){
                let idx = d.adoptedStyleSheets.indexOf(css)
                if (idx > -1) {
                    var newStyleSheets = Array.from(d.adoptedStyleSheets);
                    newStyleSheets.splice(idx, 1)
                    d.adoptedStyleSheets=newStyleSheets
                }
            }
        }
    };
    e.mixins ? e.mixins.push(n) : e.mixins = [n]
})(${COMP_IDENTIFIER},\`${css}\`${hasScoped?'.replace(/\u0001/g,__scopeId_)':''})`)
            // if (hasScoped) {
            //                 css = css.replace(/\[data-v-_scope_id\]/g, "[`+__scopeId_+`]")
            //             }
        }
        let code = clientCode+"\nexport default "+COMP_IDENTIFIER+"\n";//`define((require)=>{\n`+clientCode.trimStart()+`\nreturn ${COMP_IDENTIFIER}})`
        if (filename) {
            return code + "\n//# sourceURL=" + filename + "\n";
        } else {
            return code;
        }
    }
    return "export default {}"
}
